Proyecto - Seminario de Sistemas 2¶

EDA Monovariable y Multivariable¶

In [48]:
import pandas as pd
import geopandas as gpd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sqlalchemy import create_engine
In [49]:
conn_str = 'postgresql+psycopg2://postgres:12345@localhost/covid_data'

# Crear el motor de SQLAlchemy
engine = create_engine(conn_str)

# Consulta SQL para extraer datos
sql_query_municipios = 'SELECT * FROM municipio;'
sql_query_departmentos = 'SELECT * FROM departamento;'

# Consulta para obtener los datos de muertes por municipio junto con nombres de municipios y departamentos
sql_query_fallecidos_municipio = 'SELECT FM.id_municipio, FM.fecha, FM.fallecidos, FM.casos_mundiales, M.nombre_municipio AS nombre_municipio, D.nombre_departamento AS nombre_departamento FROM fallecidos_municipio AS FM LEFT JOIN municipio AS M ON FM.id_municipio = M.codigo_municipio LEFT JOIN departamento AS D ON M.id_departamento = D.codigo_departamento;'

# Consulta para obtener todas las muertes a nivel nacional
sql_query_muertes_mundiales = 'SELECT * FROM casos_mundiales;'

# Consulta para obtener la población total por departamento
sql_query_poblacion_departamento = 'SELECT D.codigo_departamento AS codigoDepartamento, D.nombre_departamento AS NombreDepartamento, SUM(M.poblacion) AS PoblacionTotal FROM departamento D JOIN municipio M ON D.codigo_departamento = M.id_departamento GROUP BY D.codigo_departamento, D.nombre_departamento ORDER BY D.codigo_departamento::INT;'

# Ejecutar la consulta y cargar los resultados en DataFrames
df_municipality = pd.read_sql(sql_query_municipios, engine)
df_department = pd.read_sql(sql_query_departmentos, engine)
df_municipality_deaths = pd.read_sql(sql_query_fallecidos_municipio, engine)
df_country_deaths = pd.read_sql(sql_query_muertes_mundiales, engine)
df_department_population = pd.read_sql(sql_query_poblacion_departamento, engine)


# Asegurar que la columna 'fecha' sea de tipo datetime64[ns]
df_country_deaths['fecha'] = pd.to_datetime(df_country_deaths['fecha'])

# Agrupar datos por municipio para calcular métricas necesarias
df_municipality_aggregated = df_municipality_deaths.groupby('id_municipio').agg(
    total_muertes_acumuladas=('fallecidos', 'sum'),
    promedio_nuevas_muertes=('fallecidos', 'mean')
).reset_index()

# Combinar con la información de municipios (nombre y población)
df_municipality_data = df_municipality.merge(
    df_municipality_aggregated, 
    left_on='codigo_municipio', 
    right_on='id_municipio'
)[['nombre_municipio', 'poblacion', 'promedio_nuevas_muertes', 'total_muertes_acumuladas']]

EDA Monovariable¶

Analisis de Nuevas Muertes¶

Observaciones:¶

  1. El valor promedio de nuevas muertes, es de 19.25 aproximado 19.
  2. El valor de la desviacion estandar es de 12.53, se puede observar una variabilidad significativa en los datos. Indica que las muertes nuevas varian considerablemente alrededor del valor promedio
  3. El número mínimo de muertes nuevas es 2, mientras que el máximo es 61. Esto refleja un rango bastante amplio, con valores muy bajos y muy altos, lo que puede indicar que algunos periodos han tenido eventos excepcionales (por ejemplo, picos de muertes).
In [55]:
# Estadísticas Descriptivas
describe = df_country_deaths['new_death'].describe()
print(f"Estadísticas descriptivas\n{describe}\n")

# Estadísticas de Conteo
count = df_country_deaths['new_death'].count()
print(f"Estadísticas de Conteo\n{count}\n")

# Valores únicos
unique = df_country_deaths['new_death'].unique()
nunique = df_country_deaths['new_death'].nunique()
print(f"Valores Únicos\n{unique}")
print(f"Valores Únicos (cantidad): {nunique}\n")
# Promedio
mean = df_country_deaths['new_death'].mean()
print(f"Promedio\n{mean}\n")

# Cuartiles
# Mediana (50%)
median_new_deaths = df_country_deaths['new_death'].median()

# Cuartiles (25%, 75%)
q1_new_deaths = df_country_deaths['new_death'].quantile(0.25)
q3_new_deaths = df_country_deaths['new_death'].quantile(0.75)
iqr_new_deaths = q3_new_deaths - q1_new_deaths

print("\nCuartil 25% (Q1):", q1_new_deaths)
print("Cuartil 75% (Q3):", q3_new_deaths)
print("Rango intercuartílico (IQR):", iqr_new_deaths)

# Límites para identificar outliers
lower_bound = q1_new_deaths - 1.5 * iqr_new_deaths
upper_bound = q3_new_deaths + 1.5 * iqr_new_deaths

print("\nLímite inferior para outliers:", lower_bound)
print("Límite superior para outliers:", upper_bound)
Estadísticas descriptivas
count    56.00000
mean     19.25000
std      12.52815
min       2.00000
25%       8.00000
50%      17.00000
75%      26.75000
max      61.00000
Name: new_death, dtype: float64

Estadísticas de Conteo
56

Valores Únicos
[ 3 23 20 25 37 15 11  5 21 13 14 35  7 17 22 10 40 12  6  9 61 42  2 16
  8 26 29 18 31 34 41 38 32 30]
Valores Únicos (cantidad): 34

Promedio
19.25


Cuartil 25% (Q1): 8.0
Cuartil 75% (Q3): 26.75
Rango intercuartílico (IQR): 18.75

Límite inferior para outliers: -20.125
Límite superior para outliers: 54.875
In [56]:
# Identificar outliers
outliers = df_country_deaths[(df_country_deaths['new_death'] < lower_bound) | 
                             (df_country_deaths['new_death'] > upper_bound)]
print("\nValores atípicos (outliers):")
print(outliers)

# Filtrar datos sin outliers
filtered_data = df_country_deaths[
    (df_country_deaths['new_death'] >= lower_bound) & 
    (df_country_deaths['new_death'] <= upper_bound)
]
Valores atípicos (outliers):
   cod_pais      fecha  new_cases  cumulative_cases  new_death  \
25       GT 2020-11-19        651            116381         61   

    cumulative_death  
25              4008  

Filtramos todos los registros de new_death que sean menores o iguales a 0. Por que las muertes reportadas como 0 no tienen significado para un analisis logaritmico.

Para el boxplot de Nuevas Muertes, se decidio dejar los outliners, ya que ayudan a identificar picos significativos, es decir picos o cambios significativos en la tendencia de fallecimientos

In [57]:
# Filtra los valores mayores que cero
filtered_data = df_country_deaths['new_death'][df_country_deaths['new_death'] > 0]

# Crea el histograma con la transformación logarítmica
sns.histplot(filtered_data, bins=20, kde=True, edgecolor='black', alpha=0.7)
plt.xlabel('Valores')
plt.ylabel('Frecuencia')
plt.title('Histograma de nuevas muertes')
plt.show()
No description has been provided for this image

Observaciones:¶

  • La mayoría de los días se registraron entre 8 y 26 nuevas muertes.
  • Existe un día en el que se registró un número inusualmente alto de muertes (61). Esto se considera un outliner, se considero dejar el dato ya que esto dentro del analisis siginifica un pico de muertes, es decir el dia con mas muertes de COVID-19
  • La distribución de las nuevas muertes presenta una ligera asimetría positiva.
In [58]:
plt.boxplot(df_country_deaths['new_death'])

plt.title('Diagrama de Caja de nuevas muertes')
plt.ylabel('Número de nuevas muertes')
plt.show()
No description has been provided for this image

Analisis de Cantidad de Muertes Acumuladas¶

Observaciones¶

  • En la variable de muertes acumuladas se puede ver una mejor distribución de los datos, ya que los cuartiles están un poco más proporcionados exceptuando los datos del primer cuartil. Esto se puede deber a que por mucho tiempo la población Guatemalteca acató medidas de prevención de tal forma que no hubieron muchos contagios al inicio.
  • El promedio es de 4081 un valor que puede ser considerado muy alto, sin embargo, debido a que se trata de estadísticas acumulativas, es entendible que este valor sea alto.
In [59]:
# Estadísticas Descriptivas
describe = df_country_deaths['cumulative_death'].describe()
print(f"Estadísticas descriptivas\n{describe}\n")

count = df_country_deaths['cumulative_death'].count()
print(f"Estadísticas de Conteo\n{count}\n")

unique = df_country_deaths['cumulative_death'].nunique()
print(f"Valores Únicos\n{unique}\n")

# Promedio
mean = df_country_deaths['cumulative_death'].mean()
print(f"Promedio\n{mean}\n")

# Mediana (50%)
median_new_deaths = df_country_deaths['cumulative_death'].median()

# Cuartiles (25%, 75%)
q1_new_deaths = df_country_deaths['cumulative_death'].quantile(0.25)
q3_new_deaths = df_country_deaths['cumulative_death'].quantile(0.75)
iqr_new_deaths = q3_new_deaths - q1_new_deaths
print("\nMediana para 'cumulative_deaths':", median_new_deaths)
print("\nCuartil 25% para 'cumulative_deaths':", q1_new_deaths)
print("\nCuartil 75% para 'cumulative_deaths':", q3_new_deaths)
print("Rango intercuartílico (IQR):", iqr_new_deaths)

lower_bound = q1_new_deaths - 1.5 * iqr_new_deaths
upper_bound = q3_new_deaths + 1.5 * iqr_new_deaths

print("\nLímite inferior para outliers:", lower_bound)
print("Límite superior para outliers:", upper_bound)
Estadísticas descriptivas
count      56.000000
mean     4081.553571
std       463.511495
min      3387.000000
25%      3649.250000
50%      4070.500000
75%      4520.250000
max      4803.000000
Name: cumulative_death, dtype: float64

Estadísticas de Conteo
56

Valores Únicos
56

Promedio
4081.5535714285716


Mediana para 'cumulative_deaths': 4070.5

Cuartil 25% para 'cumulative_deaths': 3649.25

Cuartil 75% para 'cumulative_deaths': 4520.25
Rango intercuartílico (IQR): 871.0

Límite inferior para outliers: 2342.75
Límite superior para outliers: 5826.75
In [60]:
# Identificar outliers
outliers = df_country_deaths[(df_country_deaths['cumulative_death'] < lower_bound) | 
                             (df_country_deaths['cumulative_death'] > upper_bound)]
print("\nValores atípicos (outliers):")
print(outliers)

# Filtrar datos sin outliers
filtered_data = df_country_deaths[
    (df_country_deaths['cumulative_death'] >= lower_bound) & 
    (df_country_deaths['cumulative_death'] <= upper_bound)
]
Valores atípicos (outliers):
Empty DataFrame
Columns: [cod_pais, fecha, new_cases, cumulative_cases, new_death, cumulative_death]
Index: []

Filtramos todos los registros de cumulative_death que sean menores o iguales a 0. Por que las muertes reportadas como 0 no tienen significado para un analisis logaritmico.

Para el boxplot de Muertes Acumuladas, no existen outliners entonces las graficas se generan con los datos existentes

In [61]:
# Filtra los valores mayores que cero
filtered_data = df_country_deaths['cumulative_death'][df_country_deaths['cumulative_death'] > 0]

sns.histplot(filtered_data, bins=20, kde=True, edgecolor='black', alpha=0.7)
plt.xlabel('Logaritmo de la población')
plt.ylabel('Frecuencia')
plt.title('Histograma de muertes acumuladas')
plt.show()
No description has been provided for this image

Observaciones:¶

  • La mayoría de los municipios presentan un número de nuevas muertes relativamente similar, agrupado alrededor de la mediana de 4000.
  • La ausencia de valores atípicos indica que no hay municipios con un número de nuevas muertes significativamente mayor o menor que el resto.
  • Esta grafica representa el numero de nuevas muertes a nivel nacional, por ende los datos representan un nviel de agregacion alto.
In [91]:
plt.boxplot(df_country_deaths['cumulative_death'])

plt.title('Diagrama de Caja de Número de Muertes Acumuladas')
plt.ylabel('Número de nuevas muertes')
plt.show()
No description has been provided for this image

Analisis de Poblacion en los Municipios¶

Observaciones¶

  • Probablemente la estadística más controversial, ya que los valores tienen una separación muy grande. Esto se debe a la población en el país de Guatemala, un número muy grande de habitantes suele concentrase en ciudades muy específicas como lo son la Ciudad de Guatemala, Mixco, Villa Nueva, etc.

  • Si comparamos la población de los municipios anteriormente mencionados con algunos otros municipios del área rural, hay una diferencia de población muy grande. Y es importante tomar en cuenta que el área rural comprende la mayor parte del territorio de la República, por lo cual es entendible que tanto la gráfica de caja como la gráfica inicial del histograma posean dicha forma.

  • Como se mencionó, la gráfica inicial que tenía el histograma tenía una forma extraña, a tal punto que la misma estaba sesgada. Por lo cual se tuvo que aplicar una transformación logaritmica para componer la visualización de la misma. La transformación logarítmica "comprime" los valores grandes y hace que los datos se distribuyan de forma más uniforme, reduciendo el sesgo.

  • De igual manera por lo que se menciono anteriormente, los outliners como vemos, corresponden a municipios con poblaciones significativamente mayores en comparacion con los demas municipios. Por lo cual, para nuestro analisis, no se eliminaron estos outliners, por que son parte de nuestro analisis pero en la transformación logarítmica aplicada sobre los datos los valores extremadamente grandes se "comprimen" cuando se toma el logaritmo. Sin embargo, esto no elimina nuestros outliners, sino que solo reduce su impacto.

In [63]:
# Estadísticas Descriptivas
describe = df_municipality['poblacion'].describe()
print(f"Estadísticas descriptivas\n{describe}\n")

# Estadísticas de Conteo
count = df_municipality['poblacion'].count()
print(f"Estadísticas de Conteo\n{count}\n")

# Valores únicos
unique = df_municipality['poblacion'].nunique()
print(f"Valores Únicos\n{unique}\n")

# Promedio
mean = df_municipality['poblacion'].mean()
print(f"Promedio\n{mean}\n")

# Cuartiles
# Mediana (50%)
median_new_deaths = df_municipality['poblacion'].median()

# Cuartiles (25%, 75%)
q1_new_deaths = df_municipality['poblacion'].quantile(0.25)
q3_new_deaths = df_municipality['poblacion'].quantile(0.75)
iqr_new_deaths = q3_new_deaths - q1_new_deaths

print("\nMediana para 'Poblacion':", median_new_deaths)
print("\nCuartil 25% para 'Poblacicon':", q1_new_deaths)
print("\nCuartil 75% para 'Poblacion':", q3_new_deaths)
print("Rango intercuartílico (IQR):", iqr_new_deaths)

# Límites para identificar outliers
lower_bound = q1_new_deaths - 1.5 * iqr_new_deaths
upper_bound = q3_new_deaths + 1.5 * iqr_new_deaths

print("\nLímite inferior para outliers:", lower_bound)
print("Límite superior para outliers:", upper_bound)
Estadísticas descriptivas
count    3.370000e+02
mean     4.997144e+04
std      8.158246e+04
min      2.563000e+03
25%      1.746500e+04
50%      3.091200e+04
75%      5.852600e+04
max      1.205668e+06
Name: poblacion, dtype: float64

Estadísticas de Conteo
337

Valores Únicos
336

Promedio
49971.44213649852


Mediana para 'Poblacion': 30912.0

Cuartil 25% para 'Poblacicon': 17465.0

Cuartil 75% para 'Poblacion': 58526.0
Rango intercuartílico (IQR): 41061.0

Límite inferior para outliers: -44126.5
Límite superior para outliers: 120117.5
In [64]:
# Identificar outliers
outliers = df_municipality[(df_municipality['poblacion'] < lower_bound) | 
                             (df_municipality['poblacion'] > upper_bound)]
print("\nValores atípicos (outliers):")
print(outliers)

# Filtrar datos sin outliers
filtered_data = df_municipality[
    (df_municipality['poblacion'] >= lower_bound) & 
    (df_municipality['poblacion'] <= upper_bound)
]
Valores atípicos (outliers):
     codigo_municipio           nombre_municipio  poblacion  id_departamento
2                 101                  GUATEMALA    1205668                1
8                 501                  ESCUINTLA     166078                5
14                115                VILLA NUEVA     464528                1
15                108                      MIXCO     494561                1
17                502  SANTA LUCIA COTZUMALGUAPA     123979                5
18               1609           SAN PEDRO CARCHA     248880               16
19                116              VILLA CANALES     165026                1
23                901             QUETZALTENANGO     196867                9
26                117          SAN MIGUEL PETAPA     145417                1
29                114                  AMATITLAN     147604                1
30                110      SAN JUAN SACATEPEQUEZ     276836                1
34                106                  CHINAUTLA     121721                1
51               1406           CHICHICASTENANGO     148943               14
68               2201                    JUTIAPA     163665               22
118              1601                      COBAN     224109               16
143              2101                     JALAPA     188522               21
161              1301              HUEHUETENANGO     129232               13
193               805               MOMOSTENANGO     136909                8
252              1326                   BARILLAS     122466               13
In [65]:
filtered_data = df_municipality['poblacion'][df_municipality['poblacion'] > 0]

# Crea el histograma con la transformación logarítmica
sns.histplot(filtered_data, bins=20, kde=True, edgecolor='black', alpha=0.7)
plt.xlabel('Logaritmo de la población')
plt.ylabel('Frecuencia')
plt.title('Histograma de población')
plt.show()
No description has been provided for this image
  • El diagrama posee un sesgo, por lo cual, se hara una transformacion logaritmica
In [66]:
# Filtra los valores mayores que cero
filtered_data = df_municipality['poblacion'][df_municipality['poblacion'] > 0]

# Crea el histograma con la transformación logarítmica
sns.histplot(np.log(filtered_data), bins=20, kde=True, edgecolor='black', alpha=0.7)
plt.xlabel('Logaritmo de la población')
plt.ylabel('Frecuencia')
plt.title('Histograma de población')
plt.show()
No description has been provided for this image

Observaciones:¶

  • La presencia de outliers y el amplio rango de la caja indican una gran variabilidad en el tamaño de la población entre los municipios analizados. Hay municipios muy pequeños y otros mucho más grandes.
  • La mayoría de los municipios tienen una población relativamente pequeña, como lo indica la mediana y el primer cuartil.
  • Los outliers representan municipios con una población significativamente mayor que el promedio. Estos municipios segun la informacion del resto de graficas y calculos, son Guatemala, Mixco o Villa Nueva, que son municipios que generalmente tienen mayor concentracion de personas.
In [67]:
plt.boxplot(df_municipality['poblacion'])

plt.title('Diagrama de Caja de Población')
plt.ylabel('Número de nuevas muertes')
plt.show()
No description has been provided for this image

Diagramas de Barras para Variables cualitativas¶

Se analiza la cantidad de veces que un municipio o departamente (Dependiendo de la grafica) aparece en los registros de nuestra base de datos.

Observaciones¶

  • Importante tomar en cuenta que hay municipios como San Lorenzo, Santa Barbara, San Pedro Sacatepequez, La Libertad y la Democracia que aparecen más veces en los registros, esto puede influir en los resultados finales.
  • Los departamentos que mas aparecen son Huehuetenango, San Marcos y Quetzaltenango, esto no debería representar una alteración en los datos ya que esto depende de la cantidad de municipios que cada departamento tenga.
In [68]:
plt.figure(figsize=(80, 6))
sns.countplot(x='nombre_municipio', data=df_municipality_deaths)
plt.xticks(rotation=45, ha='right')
plt.title('Cantidad de Veces que Aparece Cada Municipio')
plt.xlabel('Municipio')
plt.ylabel('Cantidad de Veces')
plt.show()
No description has been provided for this image
In [69]:
# Gráfica de barras para departamento
plt.figure(figsize=(10, 6))
sns.countplot(x='nombre_departamento', data=df_municipality_deaths)
plt.xticks(rotation=45, ha='right')
plt.title('Cantidad de Veces que Aparece Cada Departamento')
plt.xlabel('Departamento')
plt.ylabel('Cantidad de Veces')
plt.show()
No description has been provided for this image

EDA Multivariable¶

Graficas de Dispersion (Poblacios vs Muertes Prometio por Municipio y Poblacion vs Muertes Acumuladas por Municipio)¶

Observaciones¶

  • En la grafica de dispersión (Poblacion vs Muertes Promedio), se puede observar que hay municipios con poca población que parecen tener un promedio de nuevas muertes bajo o cercano a cero. Esto puede ser esperado, ya que municipios más pequeños generalmente tienen menos casos y, por lo tanto, menos muertes en promedio. Hay algunos municipios con poblaciones más grandes que tienen un promedio de nuevas muertes relativamente alto. Esto podría ser indicativo de una mayor densidad poblacional o de otros factores de riesgo en esos lugares.
In [92]:
# Gráfica Población vs Nuevas Muertes Promedio
plt.figure(figsize=(10, 6))
sns.scatterplot(
    data=df_municipality_data, 
    x='poblacion', 
    y='promedio_nuevas_muertes', 
    hue='nombre_municipio', 
    size='promedio_nuevas_muertes', 
    sizes=(50, 300)
)
plt.title('Población vs Nuevas Muertes Promedio por Municipio')
plt.xlabel('Población')
plt.ylabel('Promedio Nuevas Muertes')
plt.show()
No description has been provided for this image

Observaciones (Grafica Poblacion vs Muertes Acumuladas)¶

  • Como se esperaba, municipios más grandes parecen tener un número más alto de muertes acumuladas en general, aunque no de manera uniforme. Por ejemplo, algunos municipios grandes, como Guatemala, pueden tener valores más altos en muertes acumuladas.

  • Algunos puntos cercanos a la parte inferior del gráfico, con poblaciones bajas, tienen pocos casos de muertes acumuladas, lo cual es coherente con lo esperado en áreas menos densamente pobladas.

In [93]:
# Gráfica Población vs Muertes Acumuladas
plt.figure(figsize=(10, 6))
sns.scatterplot(
    data=df_municipality_data, 
    x='poblacion', 
    y='total_muertes_acumuladas', 
    hue='nombre_municipio', 
    size='total_muertes_acumuladas', 
    sizes=(50, 300)
)
plt.title('Población vs Muertes Acumuladas por Municipio')
plt.xlabel('Población')
plt.ylabel('Total Muertes Acumuladas')
plt.grid(True)
plt.show()
No description has been provided for this image

Observaciones (Municipio vs Poblacion)¶

  • Esta gráfica de dispersión nos confirma precisamente lo que se mencionaba en puntos anteriores, a pesar de que la ciudad de Guatemala es la ciudad con más habitantes en el país (con una diferencia abismal), el territorio Guatemalteco se compone en su mayoría por municipios que no poseen una población tan grande como la ciudad de Guatemala, lo cual provoca que los datos se encuentren más agrupados en la mayoría del país, mientras que la ciudad de Guatemala se encuentra demasiado dispersa.
In [72]:
plt.figure(figsize=(15, 50))
plt.scatter(df_municipality['poblacion'], df_municipality['nombre_municipio'])
plt.xlabel('Población')
plt.ylabel('Municipio')
plt.title('Dispersión: Municipio vs Población')
plt.show()
No description has been provided for this image

Observaciones¶

  • Una gráfica muy similar a la anterior, sin embargo, ahora que se analiza la población por departamento, podemos observar que los datos se encuentran más dispersos, esto se debe a que al ser porciones de territorio más grandes la diferencia entre poblaciones tiende a ser mayor.
In [73]:
plt.scatter(df_department_population['poblaciontotal'], df_department_population['nombredepartamento'])
plt.xlabel('Población')
plt.ylabel('Departamento')
plt.title('Dispersión: Departamento vs Población')
plt.show()
No description has been provided for this image

Graficas para datos cualitativos¶

Observacion¶

  • Estas gráficas muestran la cantidad de días en los que cada municipio ha registrado al menos una muerte. En ese caso ya podemos observar algunas variaciones en comparación a las estadísticas de población, ya que, a pesar de que la ciudad de Guatemala sigue siendo el número 1, ya la diferencia se reduce bastante (principalmente porque el contexto de la gráfica es otro).
  • La gráfica también nos muestra otras variaciones, como por ejemplo la ciudad de Quetzaltenango, ya que, a pesar de que es la número 7 en la gráfica de población, en esta gráfica se encuentra en el puesto 3. Esto se puede deber al comercio que se da en esta ciudad que a pesar de no tener tantos habitantes como otras ciudades, el comercio si es muy relevante.
In [74]:
# Filtrar las filas donde total_deaths no es igual a cero
df_filtered = df_municipality_deaths[df_municipality_deaths['fallecidos'] != 0]

# Contar las ocurrencias de cada "name" en el DataFrame filtrado
df_municipality_count = df_filtered['nombre_municipio'].value_counts().reset_index()
df_municipality_count.columns = ['nombre_municipio', 'count']

# Crear una gráfica de barras con seaborn
plt.figure(figsize=(10, 50))
sns.barplot(x='count', y='nombre_municipio', data=df_municipality_count) 

# Añadir etiquetas y título
plt.xlabel('Cantidad de veces (count)')
plt.ylabel('Municipio')
plt.title('Conteo de Días con Nuevas Muertes por Municipio')

# Mostrar el gráfico
plt.show()
No description has been provided for this image
In [95]:
df_filtered = df_municipality_deaths[df_municipality_deaths['fallecidos'] != 0]

# Contar las ocurrencias de cada "nombre_municipio" en el DataFrame filtrado
df_municipality_count = df_filtered['nombre_municipio'].value_counts().reset_index()
df_municipality_count.columns = ['nombre_municipio', 'count']

# Crear un mapa de calor
plt.figure(figsize=(12, 70)) 
sns.heatmap(df_municipality_count.pivot_table(index='nombre_municipio', values='count', aggfunc='sum'), cmap='YlGnBu', annot=True, fmt='g')

# Añadir título
plt.title('Mapa de Calor: Días con Nuevas Muertes por Municipio')

# Mostrar el gráfico
plt.show()
No description has been provided for this image

Departamento vs Nuevas Muertes¶

Observaciones¶

  • En esta grafica la tendencia es nuevamente al departamento de Guatemala, ya que este posee una gran cantidad de municipios que poseían un alto indice de fallecimientos por covid.
  • Podemos observar a simple vista que los departamentos con mayor presencia de municipios urbanos son aquellos que han sido más afectados. Sin embargo hay casos como el de San Marcos, donde se nota a simple vista que ha sido muy afectado, pero éste es de los pocos casos donde hay gran presencia de área rural y el covid ha afectado fuertemente.
  • El caso de San Marcos puede darse debido a ser aledaño al departamento de Quetzaltengo
In [96]:
df_filtered = df_municipality_deaths[df_municipality_deaths['fallecidos'] != 0]

df_municipality_count = df_filtered['nombre_departamento'].value_counts().reset_index()
df_municipality_count.columns = ['nombre_departamento', 'count']

plt.figure(figsize=(10, 10)) 
sns.barplot(x='count', y='nombre_departamento', data=df_municipality_count)

# Añadir etiquetas y título
plt.xlabel('Cantidad de veces (count)')
plt.ylabel('Municipio')
plt.title('Conteo de Días con Nuevas Muertes por Departamento')

# Mostrar el gráfico
plt.show()
No description has been provided for this image
In [77]:
df_municipality_count = df_filtered['nombre_departamento'].value_counts().reset_index()
df_municipality_count.columns = ['nombre_departamento', 'count']

sns.heatmap(df_municipality_count.pivot_table(index='nombre_departamento', values='count', aggfunc='sum'), cmap='YlGnBu', annot=True, fmt='g')

# Añadir título
plt.title('Mapa de Calor: Días con Nuevas Muertes por Departamento')

# Mostrar el gráfico
plt.show()
No description has been provided for this image

Municipios vs Poblacion¶

Observaciones¶

  • La Grafica que denota la poblacion de cada municipio del pais, posee un comportamiento similar al de la gráfica de dispersión anteriormente monstrada.
  • Podemos observar y notar a simple vista que los municipios pertenecientes al área urbana poseen la mayor concentración de pobladores, esto se da porque el comercio se da de una forma más abundante en estás áreas.
In [78]:
# Crear una gráfica de barras con seaborn
plt.figure(figsize=(10, 50))
sns.barplot(x='poblacion', y='nombre_municipio', data=df_municipality)

# Añadir etiquetas y título
plt.xlabel('Población')
plt.ylabel('Municipio')
plt.title('Municipio vs Población')

# Mostrar el gráfico
plt.show()
No description has been provided for this image
In [79]:
# Crear un mapa de calor con seaborn
plt.figure(figsize=(12, 70)) 
sns.heatmap(df_municipality.pivot_table(index='nombre_municipio', values='poblacion', aggfunc='sum'), cmap='YlGnBu', annot=True, fmt='g')

# Añadir título
plt.title('Mapa de Calor: Población por Municipio')

# Mostrar el gráfico
plt.show()
No description has been provided for this image

Departamento vs Poblacion¶

Observaciones¶

  • Se puede observar a simple vista que la diferencia entre poblaciones es más grande cuando englobamos los departamentos, esto debido a que hay departamentos que contienen varios municipios del área urbana.
  • Se destaca el municipio de Alta Verapaz, en el cual la influencia del municipio de Cobán juega un rol muy importante para obtener una población aceptable.
In [80]:
sns.barplot(x='poblaciontotal', y='nombredepartamento', data=df_department_population) 

# Añadir etiquetas y título
plt.xlabel('Población')
plt.ylabel('Departamento')
plt.title('Departamento vs Población')

# Mostrar el gráfico
plt.show()
No description has been provided for this image
In [81]:
# Crear un mapa de calor con seaborn
sns.heatmap(df_department_population.pivot_table(index='nombredepartamento', values='poblaciontotal', aggfunc='sum'), cmap='YlGnBu', annot=True, fmt='g')

# Añadir título
plt.title('Mapa de Calor: Población por Departamento')

# Mostrar el gráfico
plt.show()
No description has been provided for this image

Municipio vs Muertes Acumuladas¶

Observaciones¶

  • La situación de los municipios de Guatemala, Mixco y Villa Nueva fue sumamente preocupante, ya que la cantidad de personas que fallecieron en esos lugares fue muy alta. Es cierto que esto se debió a que su población era considerablemente mayor, por lo cual la recomendación primordial en ese momento hubiera sido implementar medidas para evitar que las muertes siguieran multiplicándose.
  • Si se obviaban estos tres municipios, también era importante centrarse en el municipio de Quetzaltenango. A pesar de que la cantidad de fallecidos fue considerablemente menor en comparación con Guatemala, Mixco y Villa Nueva, la situación en Quetzaltenango también requería especial atención.
In [82]:
sum_deaths_by_municipality = df_municipality_deaths.groupby('nombre_municipio')['fallecidos'].sum().reset_index()

plt.figure(figsize=(10, 50))
sns.barplot(x='fallecidos', y='nombre_municipio', data=sum_deaths_by_municipality) 

# Añadir etiquetas y título
plt.xlabel('Muertes Acumuladas')
plt.ylabel('Municipio')
plt.title('Municipio vs Muertes Acumuladas')

# Mostrar el gráfico
plt.show()
No description has been provided for this image
In [97]:
# Filtrar las filas donde "nombre_municipio" no sea igual a "GUATEMALA" "MIXCO" O "VILLA NUEVA"
df_filtered = df_municipality_deaths.query('nombre_municipio not in ["GUATEMALA", "MIXCO", "VILLA NUEVA"]')

# Agrupar por "nombre_municipio" y sumar la cantidad total de muertes
sum_deaths_by_municipality = df_filtered.groupby('nombre_municipio')['fallecidos'].sum().reset_index()

plt.figure(figsize=(10, 50))
sns.barplot(x='fallecidos', y='nombre_municipio', data=sum_deaths_by_municipality) 

# Añadir etiquetas y título
plt.xlabel('Muertes Acumuladas')
plt.ylabel('Municipio')
plt.title('Municipio vs Muertes Acumuladas (Sin Ciudad de Guatemala, Mixco y Villa Nueva)')

# Mostrar el gráfico
plt.show()
No description has been provided for this image
In [84]:
sum_deaths_by_municipality = df_municipality_deaths.groupby('nombre_municipio')['fallecidos'].sum().reset_index()

plt.figure(figsize=(12, 70)) 
# Crear un mapa de calor con seaborn
sns.heatmap(sum_deaths_by_municipality.pivot_table(index='nombre_municipio', values='fallecidos', aggfunc='sum'), cmap='YlGnBu', annot=True, fmt='g')

# Añadir título
plt.title('Mapa de Calor: Muertes Acumuladas por municipio')

# Mostrar el gráfico
plt.show()
No description has been provided for this image

Departamento vs Muertes Acumuladas¶

Observaciones¶

Importante destacar, que como ya se vio la tendencia del departamento de Guatemala, en esta grafica, se obviaron estos datos, para analizar la situacion del resto de departamentos

  • Además de la casi obvia situación del departamento de Guatemala, la gráfica también nos denota ver la situación del departamento de Quetzaltenango, ya que en anteriores gráficas pudimos ver que solo en el municipio de Quetzaltenango habían aproximadamente 36 fallecimientos, mientras que aquí podemos ver que el departamento de quetzaltenango completo tiene aproximadamente 63 muertes, lo cual nos indica que la mayor parte proviene de la cabecera municipal.
  • Importante destacar el manejo de la pandemia en departamentos como Jalapa o Santa Rosa, los cuales no reportaron hasta la fecha de estos informes grandes cantidades de fallecimientos.
In [85]:
sum_deaths_by_municipality = df_municipality_deaths.groupby('nombre_departamento')['fallecidos'].sum().reset_index()

sns.barplot(x='fallecidos', y='nombre_departamento', data=sum_deaths_by_municipality) 

# Añadir etiquetas y título
plt.xlabel('Muertes Acumuladas')
plt.ylabel('Departamento')
plt.title('Departamento vs Muertes Acumuladas')

# Mostrar el gráfico
plt.show()
No description has been provided for this image
In [86]:
# Filtrar las filas donde "nombre_municipio" no sea igual a "GUATEMALA" Transformación
df_filtered = df_municipality_deaths.query('nombre_departamento not in ["GUATEMALA"]')

# Agrupar por "nombre_municipio" y sumar la cantidad total de muertes
sum_deaths_by_municipality = df_filtered.groupby('nombre_departamento')['fallecidos'].sum().reset_index()

sns.barplot(x='fallecidos', y='nombre_departamento', data=sum_deaths_by_municipality) 

# Añadir etiquetas y título
plt.xlabel('Muertes Acumuladas')
plt.ylabel('Departamento')
plt.title('Departamento vs Muertes Acumuladas (Sin Guatemala)')

# Mostrar el gráfico
plt.show()
No description has been provided for this image
In [87]:
sum_deaths_by_municipality = df_municipality_deaths.groupby('nombre_departamento')['fallecidos'].sum().reset_index()

# Crear un mapa de calor con seaborn
sns.heatmap(sum_deaths_by_municipality.pivot_table(index='nombre_departamento', values='fallecidos', aggfunc='sum'), cmap='YlGnBu', annot=True, fmt='g')

# Añadir título
plt.title('Mapa de Calor: Muertes Acumuladas por Departamento')

# Mostrar el gráfico
plt.show()
No description has been provided for this image

Observaciones (Matriz de Correlacion de Pearson):¶

El mapa utiliza el coeficiente de correlación de Pearson, que mide la fuerza y dirección de una relación lineal entre dos variables. Un valor de 1 indica una correlación positiva perfecta (cuando una variable aumenta, la otra también), -1 indica una correlación negativa perfecta (cuando una variable aumenta, la otra disminuye), y 0 indica que no hay correlación lineal.

Los valores de correlación en el mapa son muy cercanos a 1, lo que indica una correlación positiva muy fuerte entre todas las variables. Esto significa que:

  • A medida que aumenta la población, también aumenta el promedio de nuevas muertes y el total de muertes acumuladas.
  • A medida que aumenta el promedio de nuevas muertes, también aumenta el total de muertes acumuladas.

Esta alta correlación positiva es esperable en muchos contextos, especialmente en el análisis de datos epidemiológicos (Como lo es nuestro caso de analisis). Una población más grande generalmente tendrá un mayor número de casos y, por lo tanto, más muertes.

In [88]:
import seaborn as sns
import matplotlib.pyplot as plt

# Selección de variables para análisis de correlación
variables_numericas = df_municipality_data[['poblacion', 'promedio_nuevas_muertes', 'total_muertes_acumuladas']]

# Matriz de correlación de Pearson
pearson_corr = variables_numericas.corr(method='pearson')
print("Matriz de correlación de Pearson:\n", pearson_corr)

# Gráfico de calor de la correlación
plt.figure(figsize=(8, 6))
sns.heatmap(pearson_corr, annot=True, cmap='coolwarm', fmt='.2f', linewidths=0.5)
plt.title('Mapa de Calor - Correlación de Pearson')
plt.show()
Matriz de correlación de Pearson:
                           poblacion  promedio_nuevas_muertes  \
poblacion                  1.000000                 0.898315   
promedio_nuevas_muertes    0.898315                 1.000000   
total_muertes_acumuladas   0.898315                 1.000000   

                          total_muertes_acumuladas  
poblacion                                 0.898315  
promedio_nuevas_muertes                   1.000000  
total_muertes_acumuladas                  1.000000  
No description has been provided for this image

Observaciones (Correlacion de Kendall):¶

La correlación entre la población y el promedio de nuevas muertes, así como el total de muertes acumuladas, es de 0.28. Este valor indica una correlación positiva débil. Esto sugiere que a medida que aumenta la población, hay una ligera tendencia a que aumenten también las muertes, pero esta relación no es muy fuerte.

La correlación entre estas dos variables es de 1.00. Esto indica una correlación positiva perfecta. Es lógico, ya que el total de muertes acumuladas es la suma de las nuevas muertes a lo largo del tiempo. Si aumentan las nuevas muertes, necesariamente aumentará también el total acumulado.

Comparación con la matriz de Pearson:¶

Si comparamos esta matriz con la anterior basada en el coeficiente de Pearson, podemos notar algunas diferencias:

  • La correlación de Kendall entre la población y las muertes es más débil que la correlación de Pearson. Esto podría indicar que la relación entre estas variables no es estrictamente lineal.
  • Tanto Kendall como Pearson muestran una correlación perfecta entre estas dos variables, lo que confirma la relación directa entre ellas.

Aunque existe una ligera tendencia positiva, la relación entre la población y el número de muertes no es muy fuerte. Esto podría deberse a otros factores que influyen en el número de muertes, como la edad promedio de la población, la tasa de vacunación, etc.

In [98]:
# Calcular la matriz de correlación de Kendall
kendall_corr = df_municipality_data[['poblacion', 'promedio_nuevas_muertes', 'total_muertes_acumuladas']].corr(method='kendall')

# Mostrar la matriz de correlación
print("Matriz de correlación de Kendall:")
print(kendall_corr)

import seaborn as sns
import matplotlib.pyplot as plt

# Calcular la matriz de correlación de Kendall
kendall_corr = df_municipality_data[['poblacion', 'promedio_nuevas_muertes', 'total_muertes_acumuladas']].corr(method='kendall')

# Graficar la matriz de correlación de Kendall como un mapa de calor
plt.figure(figsize=(8, 6))
sns.heatmap(kendall_corr, annot=True, cmap='coolwarm', linewidths=0.5, fmt='.2f', vmin=-1, vmax=1)
plt.title('Matriz de Correlación de Kendall')
plt.show()
Matriz de correlación de Kendall:
                          poblacion  promedio_nuevas_muertes  \
poblacion                   1.00000                  0.27989   
promedio_nuevas_muertes     0.27989                  1.00000   
total_muertes_acumuladas    0.27989                  1.00000   

                          total_muertes_acumuladas  
poblacion                                  0.27989  
promedio_nuevas_muertes                    1.00000  
total_muertes_acumuladas                   1.00000  
No description has been provided for this image

Comparación con la matriz de Pearson y Kendall:¶

  • Los resultados de Spearman son bastante similares a los obtenidos con Kendall. Ambas medidas indican una correlación positiva débil entre la población y las muertes, y una correlación positiva perfecta entre las nuevas muertes y el total acumulado.
  • Aunque la tendencia general es similar, los valores específicos de correlación pueden variar ligeramente entre Pearson, Spearman y Kendall. Esto se debe a que cada coeficiente mide diferentes aspectos de la relación entre las variables.

Al igual que en los análisis anteriores, la relación entre la población y el número de muertes es débil. Esto sugiere que otros factores, además del tamaño de la población, influyen en el número de muertes.

La correlación perfecta entre estas dos variables confirma la relación directa y esperable entre ellas.

In [90]:
# Calcular la matriz de correlación de Spearman
spearman_corr = df_municipality_data[['poblacion', 'promedio_nuevas_muertes', 'total_muertes_acumuladas']].corr(method='spearman')

# Graficar la matriz de correlación de Spearman como un mapa de calor
plt.figure(figsize=(8, 6))
sns.heatmap(spearman_corr, annot=True, cmap='coolwarm', linewidths=0.5, fmt='.2f', vmin=-1, vmax=1)
plt.title('Matriz de Correlación de Spearman')
plt.show()
No description has been provided for this image

Conclusiones:¶

  1. Los municipios que fueron más afectados durante la pandemia COVID-19, fueron aquellos pertenecientes al área urbana y esto puede ser consecuencia del estilo de vida que las personas tienen en estas áreas, además de la población tan grande que habita estos lugares. Recordemos que en su mayoria el area rural, cuenta con espacios abiertos, que ayudan a que el aire circule de mejor manera que en el area urbana.

  2. La pandemia dejó claro que el balance entre comercio y salud pública es esencial. Los comerciantes y empresas que implementaron medidas de prevención, como reuniones virtuales, comercio al aire libre y protocolos de bioseguridad, lograron minimizar el impacto de la pandemia en sus comunidades.

  3. Algunos municipios rurales, como Chinautla, Coatepeque, Huehuetenango, Puerto Barrios, entre otros, tuvieron un incremento notable de casos y muertes. A pesar de contar con menor densidad poblacional, estos municipios vieron un aumento en las muertes probablemente debido a factores como la falta de infraestructura de salud adecuada, el acceso limitado a servicios médicos u otros.

  4. En 2020 (Hasta la fecha donde se tomaron los datos), algunos municipios aún no habían reportado muertes por COVID-19, lo que genera dudas sobre la veracidad de los datos. En algunos casos, podría haberse tratado la falta de monitorizacion o documentacion de los datos o bien la falta de acceso a servicios médicos adecuados.

  5. A lo largo de la pandemia, varios municipios y departamentos demostraron ser efectivos en la contención del virus, lo que resultó en una menor tasa de mortalidad.